﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using RabiitmqWebApi.Model;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using System.Data.Common;
using System.Threading.Channels;
using RabbitMQ.Client.Events;

namespace RabiitmqWebApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        public ProductController()
        {

        }

        /// <summary>
        /// 创建商品
        /// 总结：创建商品。已经完成。
        /// 不严谨。
        /// 情况1：rabbitmq给商品微服务发消息期间，商品微服务宕机。导致：消息丢失。
        ///        消息应答机制。消息确认---->ack
        /// 总结：消息确认，和重复消费。
        /// 
        /// 情况2：rabbitmq给商品微服务发了消息，商品微服务收到消息。
        ///        商品微服务发送确认消息给rabbitmq期间。执行业务逻辑失败了。
        ///        导致：消息重复消费
        /// 方案：手动确认
        /// 
        /// 情况3：消息堆积，还有一个情况，就是商品微服务来不及处理，导致的堆积
        ///       方案：使用商品微服务集群
        ///       商品微服务集群缺陷：无法控制集群实例的强弱
        ///       所以：使用QOS来解决。
        ///       
        /// 创建商品的业务场景
        /// 
        /// 创建商品的时候，1、创建商品，2、发送短信
        /// </summary>
        /// <returns></returns>
        [HttpPost("ProductUpdate")]
        public void ProductUpdate([FromBody] Product product)
        {
            string msg = JsonConvert.SerializeObject(product);
            var body = Encoding.UTF8.GetBytes(msg);
            IConnectionFactory factory = new ConnectionFactory//创建连接工厂对象
            {
                HostName = "192.168.60.129",//IP地址
                VirtualHost = "/",
                Port = 5672,//端口号
                RequestedHeartbeat = TimeSpan.FromSeconds(3), // 心跳超时时间（秒）
                NetworkRecoveryInterval = TimeSpan.FromSeconds(3),  //客户端在重新尝试恢复连接之前等待的时间。 等待时间倍数 
                RequestedConnectionTimeout = TimeSpan.FromSeconds(2), //连接尝试的超时设置。 
                AutomaticRecoveryEnabled = true,  //设置为false表示禁用自动连接恢复。
                TopologyRecoveryEnabled = true,//支持异步发送消息
                //DispatchConsumersAsync = true,
                UserName = "admin",//用户账号
                Password = "123456"//用户密码
            };
            IConnection con = factory.CreateConnection();//创建连接对象
            IModel channel = con.CreateModel();//创建连接会话对象

            #region  Fanout 广播交换机
            {

                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "amq.fanout",
                //                    type: "fanout",
                //                    durable: true //是否持久化,true持久化
                //                    );
                ////声明一个队列
                ////  channel.QueueDeclare(
                ////    queue: "hello.one",//消息队列名称

                ////    durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。 所有消息持久化
                ////    exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                ////    autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                ////    arguments: null //设置队列的一些其它参数
                ////     );
                ////  channel.QueueBind(queue: "hello.one",
                ////exchange: "amq.fanout",
                ////routingKey: "green");

                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）
                //channel.BasicPublish(
                //    exchange: "amq.fanout",
                //    routingKey: "",
                //    mandatory: true,
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region Direct  直连交换机
            {
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "one.Direct",
                //                    type: ExchangeType.Direct,
                //                    durable: true //是否持久化,true持久化
                //                    );

                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）
                //channel.BasicPublish(
                //    exchange: "one.Direct",
                //    routingKey: "one",
                //    mandatory: true,
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region Topic 主题交换机
            {
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "one.Topic",
                //                    type: ExchangeType.Topic,
                //                    durable: true //是否持久化,true持久化
                //                    );

                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）
                //channel.BasicPublish(
                //    exchange: "one.Topic",
                //    routingKey: "sms.product.update",
                //    mandatory: true,
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region herder 死信交换机
            {

                //IModel channe2 = _Connection.CreateModel();//创建连接会话对象
                //channe2.ExchangeDeclare(exchange: "sixin.hou", type: ExchangeType.Direct, true);
                //channe2.QueueDeclare(queue: "sixin.hou.quque.two",
                //durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //arguments: null //设置队列的一些其它参数
                //);
                //channe2.QueueBind(queue: "sixin.hou.quque.two", exchange: "sixin.hou", routingKey: "sixin.hou.quque");


                //IDictionary<string, object> arguments = new Dictionary<string, object>();
                //arguments.Add("x-dead-letter-exchange", "sixin.hou");
                //arguments.Add("x-dead-letter-routing-key", "sixin.hou.quque");
                //channel.ExchangeDeclare(exchange: "sixin.yuan", type: ExchangeType.Direct, true);
                //channel.QueueDeclare(queue: "sixin.yuan.quque",
                //           durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //  arguments: arguments //设置队列的一些其它参数
                //  );
                //channel.QueueBind("sixin.yuan.quque", "sixin.yuan",routingKey : "sixin.yuan.quque");


                //IBasicProperties basicProperties = channel.CreateBasicProperties();
                //basicProperties.DeliveryMode = 2;
                //basicProperties.Expiration = "5000";
                //channel.BasicPublish(exchange: "sixin.yuan",
                //                     routingKey: "sixin.yuan.quque",
                //                     basicProperties: basicProperties,
                //                     body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region  插件 延迟消息功能的插件
            {
                channel.ExchangeDeclare(exchange: "delay.direct", type: "x-delayed-message", durable: true, arguments: new Dictionary<string, object>
                {
                    { "x-delayed-type", "direct" }
                });
                channel.QueueDeclare(queue: "delay.quequ",
                         durable: true,
                exclusive: false,
                autoDelete: false,
                arguments: null);

                channel.QueueBind("delay.quequ", "delay.direct", "delay");
                IBasicProperties basicProperties = channel.CreateBasicProperties();
                basicProperties.DeliveryMode = 2;
                basicProperties.Headers = (new Dictionary<string, object>
                {
                    { "x-delay", 5000 } // 延迟时间为5000毫秒
                });
                for (var i = 0; i < 20; i++)
                {
                    channel.BasicPublish("delay.direct", "delay", true, basicProperties, body);
                }
            }
            #endregion

            #region  消息消费成功回调通知
            {
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "CallBack.Direct",
                //                    type: ExchangeType.Direct,
                //                    durable: true //是否持久化,true持久化
                //                    );
                //channel.QueueDeclare(queue: "CallBack",
                //           durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //  arguments: null //设置队列的一些其它参数
                //  );
                //channel.QueueBind(queue: "CallBack",
                // exchange: "CallBack.Direct",
                // routingKey: "CallBack");
                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）

                ////申明回调队列
                //properties.ReplyTo = "CallBackQieue";
                //properties.CorrelationId = Guid.NewGuid().ToString();
                //channel.QueueDeclare(queue: "CallBackQieue",
                //     durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //     exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //     autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //     arguments: null //设置队列的一些其它参数
                //     );

                //channel.BasicPublish(
                //    exchange: "CallBack.Direct",
                //    routingKey: "CallBack",
                //    mandatory: true,
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}


                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个
                
                ////消费者消费成功 回调通知
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channel);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine(ea.BasicProperties.CorrelationId);
                //    Console.WriteLine($" 消息回调通知成功 {message}");
                //    channel.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                ////开始监听队列
                //channel.BasicConsume(queue: "CallBackQieue",
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion
        }

        [HttpGet("Test")]
        public string Test() 
        {
            return "test";
        }

        [HttpPost("ProductAdd")]
        public void ProductAdd([FromBody] Product product)
        {
            string msg = JsonConvert.SerializeObject(product);
            var body = Encoding.UTF8.GetBytes(msg);
            IConnectionFactory factory = new ConnectionFactory//创建连接工厂对象
            {
                HostName = "192.168.60.129",//IP地址
                VirtualHost = "/",
                Port = 5672,//端口号
                RequestedHeartbeat = TimeSpan.FromSeconds(3), // 心跳超时时间（秒）
                NetworkRecoveryInterval = TimeSpan.FromSeconds(3),  //客户端在重新尝试恢复连接之前等待的时间。 等待时间倍数 
                RequestedConnectionTimeout = TimeSpan.FromSeconds(2), //连接尝试的超时设置。 
                AutomaticRecoveryEnabled = true,  //设置为false表示禁用自动连接恢复。
                TopologyRecoveryEnabled = true,//支持异步发送消息
                //DispatchConsumersAsync = true,
                UserName = "admin",//用户账号
                Password = "123456"//用户密码
            };
            IConnection con = factory.CreateConnection();//创建连接对象
            IModel channel = con.CreateModel();//创建连接会话对象

            #region  Fanout 广播交换机
            {

                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "amq.fanout",
                //                    type: "fanout",
                //                    durable: true //是否持久化,true持久化
                //                    );



                ////声明一个队列
                ////  channel.QueueDeclare(
                ////    queue: "hello.one",//消息队列名称

                ////    durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。 所有消息持久化
                ////    exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                ////    autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                ////    arguments: null //设置队列的一些其它参数
                ////     );
                ////  channel.QueueBind(queue: "hello.one",
                ////exchange: "amq.fanout",
                ////routingKey: "green");

                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）
                //channel.BasicPublish(
                //    exchange: "amq.fanout",
                //    routingKey: "",
                //    mandatory: true,  //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region Direct  直连交换机
            {
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "one.Direct",
                //                    type: ExchangeType.Direct,
                //                    durable: true //是否持久化,true持久化
                //                    );

                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）
                //channel.BasicPublish(
                //    exchange: "one.Direct",
                //    routingKey: "two",
                //    mandatory: true,    //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region Topic 主题交换机
            {
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "one.Topic",
                //                    type: ExchangeType.Topic,
                //                    durable: true //是否持久化,true持久化
                //                    );

                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）
                //channel.BasicPublish(
                //    exchange: "one.Topic",
                //    routingKey: "ems.product.add",
                //    mandatory: true,   //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region herder 死信交换机
            {
                //IDictionary<string, object> arguments = new Dictionary<string, object>();
                //arguments.Add("x-dead-letter-exchange", "sixin.hou");
                //arguments.Add("x-dead-letter-routing-key", "sixin.hou.quque");
                //channel.ExchangeDeclare(exchange: "sixin.yuan", type: ExchangeType.Direct, true);
                //channel.QueueDeclare(queue: "sixin.yuan.quque",
                //           durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //  arguments: arguments //设置队列的一些其它参数
                //  );
                //channel.QueueBind("sixin.yuan.quque", "sixin.yuan",routingKey : "sixin.yuan.quque");
                //IBasicProperties basicProperties = channel.CreateBasicProperties();
                //basicProperties.DeliveryMode = 2;
                //basicProperties.Expiration = "5000";
                //channel.BasicPublish(exchange: "sixin.yuan",
                //                     routingKey: "sixin.yuan.quque",
                //                     basicProperties: basicProperties,
                //                     body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}
            }
            #endregion

            #region  插件 延迟消息功能的插件
            {
                //channel.ExchangeDeclare(exchange: "delay.direct", type: "x-delayed-message", durable: true, arguments: new Dictionary<string, object>
                //{
                //    { "x-delayed-type", "direct" }
                //});
                //channel.QueueDeclare(queue: "delay.quequ",
                //         durable: true,
                //exclusive: false,
                //autoDelete: false,
                //arguments: null);

                //channel.QueueBind(queue: "delay.quequ", exchange: "delay.direct", routingKey: "delay");
                //IBasicProperties basicProperties = channel.CreateBasicProperties();
                //basicProperties.DeliveryMode = 2;
                //basicProperties.Headers = (new Dictionary<string, object>
                //{
                //    { "x-delay", 10000 } // 延迟时间为5000毫秒
                //});
                //for (var i = 0; i < 20; i++)
                //{
                //    channel.BasicPublish("delay.direct", "delay", true, basicProperties, body);
                //}
            }
            #endregion

            #region  消息消费成功回调通知
            {
                //channel.ConfirmSelect();//开启消息确认模式
                //                        //发布消息    
                //                        //exchange：交换机名称
                //                        //mandatory为true时，表示如果消息没有被正确路由，消息将退回消息的生产者 如果设置为false，那么broker端自动删除该消息。
                //                        //routingKey：路由键
                //                        //props：消息属性字段，比如消息头部信息等等
                //                        //body：消息主体部分
                //                        //channel.BasicReturn += (obj, eg) =>
                //                        //{

                ////};
                //channel.ExchangeDeclare(exchange: "CallBack.Direct",
                //                    type: ExchangeType.Direct,
                //                    durable: true //是否持久化,true持久化
                //                    );
                //channel.QueueDeclare(queue: "CallBack",
                //           durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //  exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //  autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //  arguments: null //设置队列的一些其它参数
                //  );
                //channel.QueueBind(queue: "CallBack",
                // exchange: "CallBack.Direct",
                // routingKey: "CallBack");
                //var properties = channel.CreateBasicProperties();
                //properties.DeliveryMode = 2;//1非持久化、2是持久化  消息如队列持久化 控制单个消息持久化（个性化）

                ////申明回调队列
                //properties.ReplyTo = "CallBackQieue";
                //properties.CorrelationId = Guid.NewGuid().ToString();
                //channel.QueueDeclare(queue: "CallBackQieue",
                //     durable: true,//是否持久化,true持久化,队列会保存磁盘,服务器重启时可以保证不丢失相关信息。
                //     exclusive: false,//是否排他,true排他的,如果一个队列声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除.
                //     autoDelete: false,//是否自动删除。true是自动删除。自动删除的前提是：致少有一个消费者连接到这个队列，之后所有与这个队列连接的消费者都断开时,才会自动删除.
                //     arguments: null //设置队列的一些其它参数
                //     );

                //channel.BasicPublish(
                //    exchange: "CallBack.Direct",
                //    routingKey: "CallBack",
                //    mandatory: true,
                //    basicProperties: properties, //控制单个消息持久化（个性化）
                //    body: body);

                ///*首先开启Confirm模式，通知消息生产者成功推送到RabbitMQ中*/
                //if (channel.WaitForConfirms())  //单条消息确认
                //{
                //    //表示消息发送成功(已经存入队列)
                //    Console.WriteLine($"【{msg}】成功发送到RabbitMQ！");
                //}
                //else
                //{
                //    Console.WriteLine($"【{msg}】发送到RabbitMQ失败！");
                //    channel.WaitForConfirmsOrDie();//如果所有消息发送成功 就正常执行, 如果有消息发送失败；就抛出异常；
                //}


                ////Qos 防止多个消费者，能力不一致，导致系统信息堆积，每一次一个消费者只成功消费一个

                ////消费者消费成功 回调通知
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                ////5. 构造消费者实例
                //var consumer = new EventingBasicConsumer(channel);

                //consumer.Received += (model, ea) =>
                //{
                //    byte[] body = ea.Body.ToArray();
                //    var message = Encoding.UTF8.GetString(body);
                //    Console.WriteLine(ea.BasicProperties.CorrelationId);
                //    Console.WriteLine($" 消息回调通知成功 {message}");
                //    channel.BasicAck(ea.DeliveryTag, multiple: true); //消息确认
                //};
                ////开始监听队列
                //channel.BasicConsume(queue: "CallBackQieue",
                //                     autoAck: false,
                //                     consumer: consumer);
            }
            #endregion
        }
    }
}
